/**
 * @file Graphics.hpp
 *
 * @date 25/12/2011
 * @author Tales 
 *
 */

#ifndef GRAPHICS_HPP_
#define GRAPHICS_HPP_

#include <SDL.h>
#include <utility>
#include "common.hpp"

namespace wolf
{
using namespace std;
class Color;


/**
 * @brief Class to manipulate SDL_Surfaces
 * @ingroup utilMod
 *
 * It's simple, you put a SDL_Surface in a Graphics, executes all needed operations, the exits it.
 *  You can, optionally, give the ownership (the responsibility to delete) to the class and operates
 *  on a temporary surface, which is deleted when it gets out of scope.
 *
 * <h1>Settings</h1>
 * There are some important setting that modifies the way the class works. It is like a state machine,
 *  so when you set a configuration it will
 */
class WOLF_DECLSPEC Graphics
{
public:
	/**
	 * @brief Constructor
	 * @param surface_ the surface
	 * @param own if true, it deletes the surface on destructor
	 */
	Graphics(SDL_Surface *surface_, bool own = false);

	/**
	 * @brief Destructor
	 */
	~Graphics();

	/**
	 * @brief Get a pixel.
	 * @return the pixel color in internal format
	 */
	Uint32 getPixelRaw(Sint16 x, Sint16 y);

	/**
	 * @brief Get a pixel.
	 * @return a pixel color on a device independent format
	 */
	Color getPixel(Sint16 x, Sint16 y);

	/**
	 * @brief Draws a pixel
	 * @param pos the position
	 */
	void drawPixel(const pair<int, int> &pos);

	/**
	 * @brief Draws a line.
	 * @param p1 initial position.
	 * @param p2 final position.
	 */
	void drawLine(const pair<int, int> &p1, const pair<int, int> & p2);

	/**
	 * @brief Draws an empty rectangle.
	 * @param p1 initial position.
	 * @param p2 final position.
	 */
	void drawRectangle(const pair<int, int> &p1, const pair<int, int> & p2);

	/**
	 * @brief Draws a filled rectangle.
	 * @param p1 initial position.
	 * @param p2 final position.
	 */
	void fillRectangle(const pair<int, int> &p1, const pair<int, int> & p2);

	/**
	 * @brief Draws an empty ellipsis.
	 * @param p1 initial position.
	 * @param p2 final position.
	 */
	void drawEllipsis(const pair<int, int> &p1, const pair<int, int> & p2);

	/**
	 * @brief Draws an filled ellipsis.
	 * @param p1 initial position.
	 * @param p2 final position.
	 */
	void fillEllipsis(const pair<int, int> &p1, const pair<int, int> & p2);

	/**
	 * @brief Blits a graphic on this.
	 * @param src source.
	 * @param position position to draw.
	 */
	void blit(const Graphics &src, const pair<int, int> &position);

	/**
	 * @brief Blits a section from a graphic on this.
	 * @param src source.
	 * @param position position to draw.
	 * @param slice the section
	 */
	void blit(const Graphics &src, const pair<int, int> &position, SDL_Rect slice);

	/**
	 * @brief Clones the surface.
	 *
	 * Actually, it creates a new surface and copies the pixels from this for the other one.
	 * @return the surface. The caller is the owner of it.
	 */
	SDL_Surface *clone();

	/**
	 * @brief Clones a slice from this.
	 * @param slice the area to copy.
	  *@return the surface. The caller is the owner of it.
	 */
	SDL_Surface *clone(SDL_Rect slice);

	/**
	 * @brief Fill an contiguous area.
	 * @param pos the start position
	 */
	void floodFill(const pair<int, int> &pos);

	/**
	 * @brief Returns the color.
	 */
	Color getColor();

	/**
	 * @brief Changes the color
	 */
	void setColor(const Color &color);

	/**
	 * @brief Returns the current color (in the surface specific format)
	 */
	Uint32 getRawColor() const;

	/**
	 * @brief Changes the current color (in the surface specific format)
	 */
	void setRawColor(Uint32 rawColor);

	/**
	 * @brief Gets the current surface.
	 * @return the surface.
	 */
	SDL_Surface *getSurface() const;

	/**
	 * @brief Changes the current surface
	 * @param surface the surface
	 * @param own true whether is responsibility to this object to free the surface. The surface will be freed when this
	 *  get out of scope or when you call setSurface again.
	 */
	void setSurface(SDL_Surface *surface, bool own = false);
private:
	/**
	 * @brief Fake copy constructor.
	 *
	 * Designing a copy constructor became a trouble, because I couldn't decide which behavior I should adopt.
	 * There was two options: We could share the same surface or we could clone it. The problem is, we want it
	 * to be intuitive and to have good performance.
	 *
	 * Sharing a surface would be simpler and have an excellent performance (only copying the pointer address
	 *  and incrementing the reference counter), but is not very intuitive. Why would we create another instance
	 *  to operate the same surface? It would be mostly useless.
	 *
	 * However, cloning a surface would have high costs, as much in memory as in processing. An as I considerate it
	 *  more intuitive, some one could disagree and think it is sharing, what would lead to huge problems. So we
	 *  leave this decision up to the user. If he wants to share, he can use getSurface() to know the surface and
	 *  pass it on constructor. If he wants to clone, well, he only have to clone().
	 */
	Graphics(const Graphics &);
	void putPixelRaw(Sint16 x, Sint16 y, Uint32 pixel);
	void putPixel(Sint16 x, Sint16 y);
	void putPixelAlpha(Sint16 x, Sint16 y);
	SDL_Surface *surface;
	Uint32 rawColor;
	bool useAlpha;//TODO: implement this and create getters and setters.
};

} /* namespace yep */
#endif /* GRAPHICS_HPP_ */
